﻿using System;
using System.Collections.Generic;
using System.Collections;

namespace System
{
    namespace E
    {
        public class ReadOnlyArray<T> : IEnumerable<T>, IList<T>, IReadOnlyList<T>
        {
            private T[] _array;
            private bool[] _set;
            /// <summary>
            /// Return the current item at the index, and can set too (only on the first time, due to it being a read only list)
            /// </summary>
            /// <param name="index">The index of the item.</param>
            /// <returns>The item</returns>
            public T this[int index]
            {
                get { return _array[index]; }
                set { if (!_set[index]) { _array[index] = value; _set[index] = true; } else { throw new InvalidOperationException("You cannot reset a value in a ReadOnlyArray!"); } }
            }
            /// <summary>
            /// Returns the list's enumerator.
            /// </summary>
            /// <returns>The inner list's enumerator.</returns>
            public IEnumerator<T> GetEnumerator()
            {
                foreach (T item in _array)
                {
                    yield return item;
                }
            }
            /// <summary>
            /// Returns the list's enumerator.
            /// </summary>
            /// <returns>The inner list's enumerator.</returns>
            IEnumerator IEnumerable.GetEnumerator()
            {
                return _array.GetEnumerator();
            }
            /// <summary>
            /// The amount of items in the read only array.
            /// </summary>
            public int Count
            {
                get { return _array.Length; }
            }
            /// <summary>
            /// Throw an exception. This is a read only collection!
            /// </summary>
            /// <param name="index">Irrelevant.</param>
            void IList<T>.RemoveAt(int index)
            {
                throw new InvalidOperationException("No modifying a readonly collection!");
            }
            /// <summary>
            /// Throw an exception. This is a read only collection!
            /// </summary>
            /// <param name="index">Irrelevant.</param>
            /// <param name="obj">Irrelevant.</param>
            void IList<T>.Insert(int index, T obj)
            {
                throw new InvalidOperationException("No modifying a readonly collection!");
            }
            /// <summary>
            /// Returns the (first) index of a specified object. Returns -1 if it is not in the collection.
            /// </summary>
            /// <param name="obj">The object to find an index of.</param>
            /// <returns>The index.</returns>
            public int IndexOf(T obj)
            {
                for (int i = 0; i < _array.Length; i++)
                {
                    if (object.Equals(obj, _array[i]))
                    {
                        return i;
                    }
                }
                return -1;
            }
            /// <summary>
            /// Another way of writing true.
            /// </summary>
            public bool IsReadOnly
            {
                get { return true; }
            }
            /// <summary>
            /// Throw an exception. This is a read only collection!
            /// </summary>
            /// <param name="obj">Irrelevant.</param>
            /// <returns>Irrelevant.</returns>
            bool ICollection<T>.Remove(T obj)
            {
                throw new InvalidOperationException("No modifying a readonly collection!");
            }
            /// <summary>
            /// Copies all of the inner it can to the array given as input.
            /// </summary>
            /// <param name="arr">The array to copy to.</param>
            /// <param name="index">The index to start copying from.</param>
            public void CopyTo(T[] arr, int index = 0)
            {
                if (index < 0 || index > arr.Length)
                {
                    throw new ArgumentException("Index invalid.");
                }
                int n = 0;
                for (int i = index; (i < arr.Length && n < _array.Length); i++, n++)
                {
                    arr[i] = _array[n];
                }
            }
            /// <summary>
            /// Does the array contain the object T? Now you know.
            /// </summary>
            /// <param name="obj">The object to check.</param>
            /// <returns>The result</returns>
            public bool Contains(T obj)
            {
                return this.IndexOf(obj) > -1;
            }
            /// <summary>
            /// Throw an exception. This is a read only collection!
            /// </summary>
            void ICollection<T>.Clear()
            {
                throw new InvalidOperationException("No modifying a readonly collection!");
            }
            /// <summary>
            /// Throw an exception. This is a read only collection!
            /// </summary>
            /// <param name="obj">Irrelevant.</param>
            void ICollection<T>.Add(T obj)
            {
                throw new InvalidOperationException("No modifying a readonly collection!");
            }
            /// <summary>
            /// Constructor.
            /// </summary>
            /// <param name="size">Size of the inner array.</param>
            public ReadOnlyArray(int size)
            {
                _array = new T[size];
                _set = new bool[size];
                for (int i = 0; i < size; i++)
                {
                    _set[i] = false;
                }
            }
        }
    }
}
